# -*- python -*-
# ex: set syntax=python:

# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# It has one job: define a dictionary named BuildmasterConfig. This
# dictionary has a variety of keys to control different aspects of the
# buildmaster. They are documented in docs/config.xhtml .

from buildbot.scheduler import Dependent
from buildbot.scheduler import Scheduler
from buildbot.scheduler import Periodic
from buildbot.schedulers import triggerable

from common import chromium_utils
from master import build_utils
from master import master_utils
from master import slaves_list
from master import status_logger
from master import pubsub_json_status_push
from master.factory import gclient_factory, annotator_factory
from master.factory.dart import dart_factory
from master.factory.dart.dart_factory import (linux_env, windows_env,
                                              linux_clang_env)
from master.factory.dart.channels import CHANNELS

import config
import master_site_config
ActiveMaster = master_site_config.DartFYI
utils = dart_factory.DartUtils(ActiveMaster)

# Hack to increase timeout for steps, dart2js debug checked mode takes more
# than 8 hours.
utils.monkey_patch_remoteshell()

MASTER_HOST = ActiveMaster.master_host
WEB_STATUS = True
MAIL_NOTIFIER = ActiveMaster.is_production_host

# This is the dictionary that the buildmaster pays attention to. We also use
# a shorter alias to save typing.
c = BuildmasterConfig = {}

config.DatabaseSetup(c)

# 'slavePortnum' defines the TCP port to listen on. This must match the value
# configured into the buildslaves (with their --master option)
c['slavePortnum'] = ActiveMaster.slave_port

slaves = slaves_list.SlavesList('slaves.cfg', 'DartFYI')

annotator = annotator_factory.AnnotatorFactory()

def setup_channel(channel):
  postfix = channel.builder_postfix

  ####### Variant definitions
  # build-base-name, category, platform, builder, tester
  # env are relative to the dart root directory.

  def category(name):
    return '%d%s%s|all' % (channel.position, name, channel.category_postfix)

  # Build and test Dart using recipes, rather than with annotated steps
  variants_dart_recipe = []

  variants_dart_recipe.append({
    'name': 'androidvm-linux' + postfix,
    'category': category('8android'),
    'factory_builder': annotator.BaseFactory(recipe='dart/misc'),
    'platform': 'android' + postfix,
    'env': linux_env,
  })

  variants_dart_recipe.append({
    'name': 'pub-win' + postfix,
    'category': category('94pub-pkg'),
    'factory_builder': annotator.BaseFactory(recipe='dart/misc'),
    'platform': 'windows' + postfix,
    'env': windows_env,
  })

  # TODO(whesse): Move these 3 builders back to client.dart master.
  variants_dart_recipe.append({
    'name': 'dart2jsdumpinfo-linux' + postfix,
    'category': category('2dart2js'),
    'factory_builder': annotator.BaseFactory(recipe='dart/misc'),
    'platform': 'posix' + postfix,
    'env': linux_env,
  })

  variants_dart_recipe.append({
    'name': 'pub-mac' + postfix,
    'category': category('94pub-pkg'),
    'factory_builder': annotator.BaseFactory(recipe='dart/misc'),
    'platform': 'posix' + postfix,
  })

  variants_dart_recipe.append({
    'name': 'pub-linux' + postfix,
    'category': category('94pub-pkg'),
    'factory_builder': annotator.BaseFactory(recipe='dart/misc'),
    'platform': 'posix' + postfix,
    'env': linux_env,
  })
# End of builders to move back to client.dart

  variants_dart_recipe.append({
    'name': 'dart2js-linux-none-debug' + postfix,
    'builddir': 'dart2js-linux-debug' + postfix,
    'category': category('2dart2js'),
    'factory_builder': annotator.BaseFactory(
        recipe='dart/dart2js'),
    'platform': 'posix' + postfix,
    'env': linux_env
  })

  variants_dart_recipe.append({
    'name': 'dart2js-linux-none-debug-hostchecked' + postfix,
    'builddir': 'dart2js-linux-debug-host-checked' + postfix,
    'category': category('2dart2js'),
    'factory_builder': annotator.BaseFactory(
        recipe='dart/dart2js'),
    'platform': 'posix' + postfix,
    'env': linux_env
  })

  variants_dart_recipe.append({
    'name': 'dart2js-mac10.11-safarimobilesim' + postfix,
    'builddir': 'mobile' + postfix,
    'category': category('90safari'),
    'factory_builder': annotator.BaseFactory(
        recipe='dart/dart2js'),
    'platform': 'posix' + postfix,
  })

  variants_dart_recipe.append({
    'name': 'ddc-linux-release' + postfix,
    'category': category('5ddc'),
    'factory_builder': annotator.BaseFactory(
        recipe='dart/ddc'),
    'platform': 'posix' + postfix,
  })

  variants_dart_recipe.append({
    'name': 'ddc-mac-release' + postfix,
    'category': category('5ddc'),
    'factory_builder': annotator.BaseFactory(
        recipe='dart/ddc'),
    'platform': 'posix' + postfix,
  })

  variants_dart_recipe.append({
    'name': 'ddc-win-release' + postfix,
    'category': category('5ddc'),
    'factory_builder': annotator.BaseFactory(
        recipe='dart/ddc'),
    'platform': 'windows' + postfix,
  })


  # VM Kernel precomp
  for platform in ['linux']:
    for arch in ['x64']:
      for mode in ['release', 'debug']:
        num_shards = 6 if mode == 'release' else 8
        for shard_id in range(1, num_shards + 1):
          variants_dart_recipe.append({
              'name': ('vm-kernel-precomp-%s-%s-%s-%s-%d'
                        % (platform, mode, arch, shard_id, num_shards)
                        + postfix),
              'category': category('1vm-kernel'),
              'factory_builder':
                  annotator.BaseFactory(recipe='dart/dart_vm_kernel'),
              'platform': 'posix',
            })

  # VM Kernel checked
  variants_dart_recipe.append({
    'name': 'vm-kernel-linux-release-x64-checked' + postfix,
    'category': category('1vm-kernel'),
    'factory_builder':
        annotator.BaseFactory(recipe='dart/dart_vm_kernel'),
    'platform': 'posix',
  })


  if channel.name == 'integration':
    variants_dart_recipe = []

  ####### Schedulers

  dart_recipe_builder_names = utils.get_builder_names(variants_dart_recipe)

  # normal builders
  c['schedulers'].append(Scheduler(
    name='fyi-main' + postfix,
    branch=channel.branch,
    treeStableTimer=0,
    builderNames=dart_recipe_builder_names,
  ))

  ####### Builders

  for b in utils.get_builders_from_variants(variants_dart_recipe, slaves, []):
    c['builders'].append(b)

c['builders'] = []
c['schedulers'] = []
for channel in CHANNELS:
  if channel.name != 'integration':
    setup_channel(channel)

####### CHANGESOURCES

c['change_source'] = [
    utils.get_github_mirror_poller('dart-lang',
                                   'sdk',
                                   branch='master',
                                   master='fyi'),
    utils.get_github_mirror_poller('dart-lang',
                                   'sdk',
                                   branch='dev',
                                   master='fyi'),
    utils.get_github_mirror_poller('dart-lang',
                                   'sdk',
                                   branch='stable',
                                   master='fyi')]

####### BUILDSLAVES

c['slaves'] = utils.get_slaves(c['builders'])

# Make sure everything works together.
master_utils.VerifySetup(c, slaves)

# Prioritize the builders depending on channel.
c['prioritizeBuilders'] = utils.prioritize_builders


####### STATUS TARGETS

# 'status' is a list of Status Targets. The results of each build will be
# pushed to these targets. buildbot/status/*.py has a variety to choose from,
# including web pages, email senders, and IRC bots.

c['status'] = [status_logger.StatusEventLogger()]

# Add in the pubsub pusher, which pushes all status updates to a pubsub
# topic.  This will not run unless is_production_host is set to True.
# This will fail on a production host if it cannot find the service
# account file.
pubsub_pusher = pubsub_json_status_push.StatusPush.CreateStatusPush(
    activeMaster=ActiveMaster)
if pubsub_pusher:
  c['status'].append(pubsub_pusher)

if WEB_STATUS:
  for status in utils.get_web_statuses():
    c['status'].append(status)

if MAIL_NOTIFIER:
  # We have people that are interested in a specific subset of the builders
  # and want to be notified whenever they break.
  mail_notifiers = [
    {
      'extraRecipients' : ['johnniwinther@google.com',
                           'karlklose@google.com',
                           'floitsch@google.com'],
      'builders' : ['dart2js-linux-debug',
                    'dart2js-linux-debug-checked',
                    'dart2js-linux-debug-host-checked',
                    'dart2js-linux-debug-checked-host_checked',
                    'dart2js-linux-release-host-checked',
                    'dart2js-linux-release-checked-host-checked'],
    },
    {
      'extraRecipients' : ['erikcorry@google.com'],
      'builders' : ['dart2js-linux-release-host-checked-minified'],
    },
    {
      'extraRecipients' : ['kmillikin@google.com',
                           'vegorov@google.com'],
      'builders' : ['vm-kernel-linux-release-x64',
                    'vm-kernel-linux-debug-x64'],
    },
  ]

  for notifier in utils.get_mail_notifier_statuses(mail_notifiers):
    c['status'].append(notifier)


# Keep last build logs, the default is too low.
c['buildHorizon'] = 1000
c['logHorizon'] = 500
# Must be at least 2x the number of slaves.
c['eventHorizon'] = 200
# Must be at least 1x the number of builds listed in console.
c['buildCacheSize'] = 60

c['properties'] = {'mastername': master_utils.GetMastername()}

####### PROJECT IDENTITY

# the 'projectName' string will be used to describe the project that this
# buildbot is working on. For example, it is used as the title of the
# waterfall HTML page. The 'projectURL' string will be used to provide a link
# from buildbot HTML pages to your project's home page.

c['projectName'] = ActiveMaster.project_name
c['projectURL'] = config.Master.project_url

# the 'buildbotURL' string should point to the location where the buildbot's
# internal web server (usually the html.Waterfall page) is visible. This
# typically uses the port number set in the Waterfall 'status' entry, but
# with an externally-visible host name which the buildbot cannot figure out
# without some help.

c['buildbotURL'] = ActiveMaster.buildbot_url
